﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDSimpleModelGenerator.Common;
using FDSimpleModelGenerator.Entities;
using FDSimpleModelGenerator.Entities.CreateTables;
using FDSimpleModelGenerator.Entities.Enums;
using FDSimpleModelGenerator.Entities.Exceptions;
using FDSimpleModelGenerator.IServices;
using Microsoft.Data.Sqlite;

namespace FDSimpleModelGenerator.Services.Sqlite
{
    /// <summary>
    /// Sqlite生成数据库表服务
    /// </summary>
    public class SqliteGenerateTableService : IGenerateTableService
    {
        private readonly IDbAccessor _dbAccessor;
        private readonly IDbConfigResolver _dbConfigResolver;
        private readonly IExceptionThrowFactory _exceptionThrowFactory;

        public DbType DbType => DbType.Sqlite;

        public SqliteGenerateTableService(IDbAccessor dbAccessor, IEnumerable<IDbConfigResolver> dbConfigResolvers,
            IExceptionThrowFactory exceptionThrowFactory)
        {
            _exceptionThrowFactory = exceptionThrowFactory;
            _dbAccessor = dbAccessor;
            _dbConfigResolver = dbConfigResolvers.First(r => r.DbType == DbType);
        }

        public GenResult Generate(DbConfig dbConfig, Table tableInfo)
        {
            _dbAccessor.Init(() => new SqliteConnection(_dbConfigResolver.GetConnectionString(dbConfig)));

            var sb = new StringBuilder();
            var sbIndex = new StringBuilder();
            sb.Append($"--{tableInfo.Description}\r\n");
            if (tableInfo.DeleteExists)
            {
                sb.Append($"DROP TABLE IF EXISTS {tableInfo.Name};\r\n");
            }
            sb.Append($"CREATE TABLE `{tableInfo.Name}`(\r\n");
            int i = 0;
            foreach (var column in tableInfo.Columns)
            {
                if (column.IncrementValue > 0 && !column.PrimaryKey)
                    _exceptionThrowFactory.Throw<GenerateException>($"{column.Name} must be both primary and auto increment column, otherwise not be auto increment column.");
                sb.Append($"\t`{column.Name}`{DbDataTypeFormatter.DataType(column.DataType, column.Length, column.Precision)}");
                sb.Append($"{DbDataTypeFormatter.AllowNull(column.AllowNulls)}");
                sb.Append($"{(column.PrimaryKey && column.IncrementValue > 0 ? " PRIMARY KEY AUTOINCREMENT" : "")}");
                //sb.Append($"{DbDataTypeFormatter.Format(column.IncrementValue.ToString(), val => " AUTOINCREMENT", val => int.TryParse(val, out int n) && n > 0, () => DbDataTypeFormatter.DefaultValue(column.DefaultValue, column.DataType))}");
                sb.Append($" {DbDataTypeFormatter.DefaultValue(column.DefaultValue, column.DataType)}");
                sb.Append($"{(i++ == tableInfo.Columns.Count() - 1 ? "" : ",")}--{column.Remark}\r\n");
            }
            //var primaryKeys = tableInfo.Columns.Where(c => c.PrimaryKey).Select(c => c.Name);
            //sb.Append($"{DbDataTypeFormatter.PrimaryKey(primaryKeys)}\r\n");
            sb.Append(");\r\n");

            GenResult resTable = new GenResult { Result = sb.ToString() };
            if (tableInfo.ExecuteSql)
            {
                resTable.IsExecuteSuccess = _dbAccessor.ExecuteNoneQuery(sb.ToString()) > 0;
                // sqlite需要先创建好表才能创建索引
            }
            if (tableInfo.Indexes.Count() > 0)
            {
                sbIndex.Append("\r\n");
                foreach (var index in tableInfo.Indexes)
                {
                    var columns = index.ToIndexColumns();
                    if (columns.Count() == 0)
                    {
                        continue;
                    }

                    var unique = index.UniqueIndex ? " UNIQUE" : "";
                    sbIndex.Append(
                        $"CREATE{unique} INDEX {DbDataTypeFormatter.IndexName(tableInfo.Name, columns)} ON {tableInfo.Name} {DbDataTypeFormatter.IndexColumns(columns)};\r\n");
                }

                if (tableInfo.ExecuteSql)
                {
                    _dbAccessor.ExecuteNoneQuery(sbIndex.ToString());
                }
                resTable.Result = $"{resTable.Result}{sbIndex}";
            }

            return resTable;
        }

        public async Task<GenResult> GenerateAsync(DbConfig dbConfig, Table tableInfo)
        {
            return await Task.Run(() => Generate(dbConfig, tableInfo));
        }
    }
}
